"""
@File    :   config.py
@Time    :   2024/01/07 20:00:53
@Author  :   Qrj
@Email   :   923207736@qq.com
@description   :   配置文件
"""

from functools import lru_cache

from pydantic_settings import BaseSettings, SettingsConfigDict

from src.business.admin.system.oauth2.auth.captcha.enums import CaptchaTypeEnum
from src.utils.path import PathUtil

# 获取server文件夹绝对路径
server_path = PathUtil.get_project_root_path()
# 获取.env文件路径
env_dir_path = PathUtil.get_project_env_path()
# 判断.env文件是否存在
if not env_dir_path.exists():
    raise Exception(".env环境配置文件不存在")
env_dir_path = env_dir_path.as_posix()


class Settings(BaseSettings):
    """应用配置"""

    # 读取.env的配置
    model_config = SettingsConfigDict(env_file=env_dir_path, env_file_encoding="utf-8")

    # 应用配置
    debug: bool = True  # DEBUG模式
    api_doc_title: str = "fastapi模板标题"  # API文档标题
    api_doc_description: str = "fastapi模板描述"  # API文档描述
    api_version: str = "v0.1.0"  # API版本号
    api_openapi_url: str | None = (
        "/openapi_json.json" if debug else None
    )  # 将其设为None表示关闭所有交互式API文档
    api_openapi_static_enable: bool = True  # 开启swagger和redoc的css与js文件本地加载
    api_docs_url: str | None = (
        "/docs" if debug else None
    )  # 将其设为None表示关闭相关API文档(redoc同)
    api_redoc_url: str | None = "/redoc" if debug else None
    api_terms_of_service: str | None = None  # 团队的官网url
    api_contact: dict[str, str] | None = {
        "name": "联系作者",
        "url": "https://www.sogou.com",
        "email": "123456@qq.com",
    }  # api的联系信息
    api_license_info: dict[str, str] | None = {
        "name": "fastapi版权信息",
        "url": "https://www.baidu.com",
    }  # 版权信息
    api_server: list[dict[str, str]] | None = [
        {"url": "/", "description": "本地调试环境"},
        {"url": "https://www.baidu.com", "description": "线上测试环境"},
        {"url": "https://www.sogou.com", "description": "线上生产环境"},
    ]  # api的服务端地址与对应备注
    host: str = "0.0.0.0"  # 服务主机
    port: int = 8000  # 端口号
    uvicorn_access_log: bool = debug  # uvicorn的access日志
    uvicorn_reload: bool = debug  # uvicorn的自动重载功能
    uvicorn_ws_max_size: int = 2000  # uvicorn的ws的最大长度
    uvicorn_workers: int = (
        1  # uvicorn进程数量(正常为1就可以了, 多进程通过gun进行启动与管理)
    )
    # CORS配置
    cors_allow_origins: list[str] = [
        "http://192.168.122.231:33333",
        "http://192.168.1.231:33333",
        "http://127.0.0.1:33333",
        "http://localhost:33333",
        "http://www.ruoyi.vip",
        "http://demo.ruoyi.vip",
        "https://www.sogou.com",
    ]
    cors_allow_credentials: bool = False  # 是否支持Cookie(默认为False)
    cors_allow_methods: list[str] = ["GET", "POST"]
    cors_allow_headers: list[str] = ["*"]
    cors_max_age: int = 600  # 浏览器缓存CORS响应的最长时间(单位秒, 默认600秒)
    # Sqlalchemy 配置(主库)
    master_orm_sync_engine_prefix: str = "mysql+pymysql"  # 同步ORM引擎前缀
    master_orm_async_engine_prefix: str = "mysql+aiomysql"  # 异步ORM引擎前缀
    master_sync_orm_url: str = ""
    master_async_orm_url: str = ""
    # Sqlalchemy 配置(主库与从库通用)
    orm_echo: bool = False  # 是否输出sql操作信息
    orm_future: bool = True  # 是否使用2.0接口(无需修改)
    orm_pool_pre_ping: bool = (
        True  # 是否在每次复用连接之前先ping, 以确保连接可用而不会报错
    )
    orm_process_pool_size: int = 50  # 单进程数据库连接池大小
    orm_auto_commit: bool = False  # 关闭自动commit(sqlalchemy默认也是不自动提交, 且不允许设置为自动提交) 因此我们的任何curd操作的execute都需要放在begin的上下文中进行
    orm_auto_flush: bool = False  # 关闭查询前自动flush(与数据库内保持一致, 需要单独刷新则单独使用session.flush)
    orm_expire_on_commit: bool = False  # sqlalchemy是否在提交后过期
    # redis 配置
    redis_host: str = ""
    redis_port: int = 6379
    redis_password: str = ""
    redis_url: str = ""
    # 静态文件配置
    static_prefix: str = "/static"  # 静态文件url路径
    static_dir_path: str = server_path.joinpath("static").as_posix()  # 静态文件路径
    # 上传文件配置
    upload_prefix: str = "/upload"  # 上传url路径
    upload_dir_path: str = server_path.joinpath("upload").as_posix()  # 上传文件路径
    upload_chunk_size: int = 25 * 1024 * 1024  # 异步上传保存时的文件分块大小
    # 登录验证码配置
    enable_user_login_captcha: bool = True  # 是否开启登录验证码
    user_login_captcha_type: CaptchaTypeEnum = (
        CaptchaTypeEnum.sliding_puzzle
    )  # 登录验证码类型
    sliding_captcha_max_error_value: int = 5  # 滑块验证码的最大误差值(单位px)
    # 默认的用户头像、oauth2客户端logo等配置(与上传文件夹的相对位置)
    default_user_avatar: str = "fixed/yl.png"  # 默认用户头像配置
    default_oauth2_client_logo: str = (
        "fixed/oauth2_client_logo.webp"  # 默认oauth2客户端logo配置
    )
    # 默认的系统租户的管理员账号与密码(在env文件中配置)
    default_system_tenant_admin_username: str = ""
    default_system_tenant_admin_password: str = ""
    # 默认的初始系统租户的管理员名称
    default_system_tenant_admin_name: str = "Lu_Xiao"
    # 文件上传默认配置
    default_upload_avatar_max_size: int = 20  # 默认最大上传用户头像的大小(单位: MB)
    default_upload_image_max_size: int = 20  # 默认最大上传图片的大小(单位: MB)
    default_upload_video_max_size: int = 200  # 默认最大上传视频的大小(单位: MB)
    default_upload_file_max_size: int = 200  # 默认最大上传视频的大小(单位: MB)
    default_allow_upload_avatar_suffix: list[str] = list(
        {
            ".png",
        }
    )  # 默认允许上传的用户头像图片格式
    default_allow_upload_image_suffix: list[str] = list(
        {
            ".jpeg",
            ".png",
            ".jpg",
            ".gif",
            ".webp",
        }
    )  # 默认允许上传的图片格式
    default_allow_upload_video_suffix: list[str] = list(
        {
            ".mp4",
            ".ogv",
            ".webm",
        }
    )  # 默认允许上传的视频格式
    default_allow_upload_file_suffix: list[str] = list(
        {
            ".ofd",
            ".xlsx",
            ".wps",
            ".xls",
            ".doc",
            ".docx",
            ".txt",
            ".csv",
            ".pdf",
            ".mp3",
            ".mp4",
            ".rar",
            ".7z",
            ".zip",
            ".dps",
            ".dpt",
            ".ppt",
            ".pot",
            ".pps",
            ".pptx",
            ".potx",
            ".ppsx",
            ".wav",
            ".avi",
            *default_allow_upload_avatar_suffix,
            *default_allow_upload_image_suffix,
            *default_allow_upload_video_suffix,
        }
    )  # 默认允许上传的文件格式
    # 密码加密配置
    bcrypt_rounds: int = 8  # bcrypt迭代次数,越大耗时越长(好在python的bcrypt是C库)
    # jwt加密配置(当前使用的是token, 因为jwt无状态, 不好通过后台控制登录)
    jwt_secret_key: str = ""
    # oauth2客户端配置
    default_oauth2_password_module_client_id: str = (
        ""  # 默认的password模式和swagger专用的password模式的客户端编号
    )
    default_oauth2_password_module_client_secret: str = (
        ""  # 默认的password模式和swagger专用的password模式的客户端密钥
    )
    oauth2_access_token_min_expiration_seconds: int = (
        60  # 访问令牌最小过期秒数(默认60秒)
    )
    oauth2_access_token_max_expiration_seconds: int = (
        21600  # 访问令牌最大过期秒数(默认6小时)
    )
    oauth2_access_token_default_expiration_seconds: int = (
        600  # 默认的访问令牌过期秒数(10分钟)
    )
    oauth2_refresh_token_min_expiration_seconds: int = (
        60  # 刷新令牌最小过期秒数(默认60秒)
    )
    oauth2_refresh_token_max_expiration_seconds: int = (
        1296000  # 刷新令牌最大过期秒数(默认15天)
    )
    oauth2_refresh_token_default_expiration_seconds: int = (
        3600  # 默认的刷新令牌过期秒数(1小时)
    )
    oauth2_authorization_code_min_expiration_seconds: int = (
        60  # 授权码最小过期秒数(默认60秒)
    )
    oauth2_authorization_code_max_expiration_seconds: int = (
        900  # 授权码最大过期秒数(默认10分钟)
    )
    oauth2_authorization_code_default_expiration_seconds: int = (
        600  # 授权码默认过期秒数(默认10分钟)
    )
    # 分页配置
    default_pagination_size: int = 15  # 默认的分页数据量
    default_max_pagination_size: int = 1000  # 默认的最大分页数据量
    # 用户密码相关默认配置
    default_min_password_length: int = 8  # 默认密码最小长度
    default_max_password_length: int = 16  # 默认密码最大长度
    # 用户登录锁定相关默认配置
    default_login_failure_lockout_times: int = 10  # 默认登录失败锁定次数
    default_login_failure_lock_minutes: int = 5  # 默认登录失败锁定时间(分钟)
    # redis的Token管理相关配置
    redis_access_token_zset_name: str = "access_token_zset"  # access_token有序集合名称
    redis_refresh_token_zset_name: str = (
        "access_token_zset"  # refresh_token有序集合名称
    )
    # funboost相关配置
    # 定时任务配置
    default_delete_expired_double_tokens_seconds: int = (
        5  # 默认的定时删除过期的双Token的时间(单位秒, 默认5秒)
    )
    default_create_image_captcha_seconds: int = (
        5  # 默认的定时创建图形验证码的时间(单位秒, 默认5秒)
    )
    default_create_image_captcha_number: int = (
        100  # 默认的定时创建图形验证码的个数(默认100个)
    )
    default_create_image_captcha_hash_table_max_couont: int = (
        2000  # 达到这个数量,funboost就不会再新往hash表中插入图形验证码(默认2000个)
    )
    default_create_sliding_captcha_seconds: int = (
        5  # 默认的定时创建滑块验证码的时间(单位秒, 默认5秒)
    )
    default_create_sliding_captcha_number: int = (
        20  # 默认的定时创建滑块验证码的个数(默认100个)
    )
    default_create_sliding_captcha_hash_table_max_couont: int = (
        1000  # 达到这个数量,funboost就不会再新往hash表中插入图形验证码(默认2000个)
    )


@lru_cache
def get_app_settings() -> Settings:
    """缓存配置

    Returns:
        Settings: 配置对象实例
    """
    settings = Settings()
    return settings
